package com.lucifer.d.security.boot;

import com.alibaba.fastjson.JSON;
import com.lucifer.d.security.annotation.verify.Auth;
import com.lucifer.d.security.annotation.verify.Space;
import com.lucifer.d.security.model.SecurityConfigModel;
import com.lucifer.d.security.service.gateway.content.SurroundContent;
import com.lucifer.d.security.service.gateway.model.AuthPacking;
import com.lucifer.d.security.service.gateway.properties.BootConfigProperties;
import com.lucifer.d.util.RedissonUtil;
import jakarta.annotation.PostConstruct;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;

/**
 * FIXME 优化项：1、存在业务锁时终止服务启动；2、redis模拟业务锁；3、原接口变更路径后，清除动作会丢失，保留原有地址配置形成脏数据
 * @author Lucifer
 * @create 2023 - 03 - 04 15:43
 */
public class MenuOrmInitServer {

    private BootConfigProperties bootConfigProperties;

    private SecurityConfigModel securityConfigModel;

    public MenuOrmInitServer(SecurityConfigModel securityConfigModel, BootConfigProperties bootConfigProperties) {
        this.securityConfigModel = securityConfigModel;
        this.bootConfigProperties = bootConfigProperties;
    }

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ConfigurableApplicationContext run;

    @PostConstruct
    public void menuOrmInit(){
        // 是否开启lucifer-security/启用网关模式过滤
        if (securityConfigModel.getOnSecurity() & bootConfigProperties.isEnable()){
            // 网关过滤中心不进行过滤图装载
            if (!bootConfigProperties.isServer()){
                // 判断是否正在进行security业务锁，如果存在业务锁，停止该项目启动
                RLock lock = RedissonUtil.getLock(redissonClient, SurroundContent.CONFIG_BOOT_LOCK);
                if (lock.isLocked()){
                    System.err.println("服务终止：security配置装载出错");
                    System.out.println("存在执行security配置服务，资源占用中，请稍后部署");
                    run.close();
                    return;
                }
                System.out.println("lucifer-security-service初始化配置：start");
                // 业务上锁
                lock.lock();
//                System.out.println("lucifer-security业务锁开启");
                try {
                    String[] beanNamesForAnnotation = run.getBeanNamesForAnnotation(RestController.class);
                    //获取类对象
                    for (String str : beanNamesForAnnotation) {
                        Object bean = run.getBean(str);
                        String className = bean.getClass().getName();
                        // 移除IOC容器代理对象类，取原始类
                        int end = className.indexOf("$");
                        className = end <= 0 ? className : className.substring(0 , end);
                        Class<?> clazz = Class.forName(className);
                        //获取requestMapping注解的类
                        RequestMapping declaredAnnotation = clazz.getAnnotation(RequestMapping.class);
                        if (declaredAnnotation != null) {
                            // 获取权限范围声明注解
                            Space space = clazz.getAnnotation(Space.class);
                            // 未声明范围视为不进行权限过滤
                            if (space != null){
                                // 获取类的url路径前缀（类RequestMapping注解）
                                String urlPrefix = urlFormat(declaredAnnotation);
                                // 各类请求协议声明载体，循环外声明，单例使用
                                GetMapping getMethod;
                                PostMapping postMethod;
                                PutMapping putMethod;
                                DeleteMapping deleteMethod;
                                String path = null;
                                AuthPacking value = null;
                                for (Method method : clazz.getDeclaredMethods()) {
                                    // 获取权限过滤声明注解
                                    Auth auth = method.getAnnotation(Auth.class);
                                    // 未声明视为不进行权限过滤
                                    if (auth != null){
                                        if ((getMethod = method.getAnnotation(GetMapping.class)) != null) {
                                            path = "GET/"+urlPrefix + (getMethod.value().length == 0 ? "" :
                                                    "/".equals(String.valueOf(getMethod.value()[0].charAt(0))) ? getMethod.value()[0] :
                                                            "/"+getMethod.value()[0]);
                                            value = AuthPacking.packing(space.value(), auth.value(),"GET", path);
                                        } else if ((postMethod = method.getAnnotation(PostMapping.class)) != null) {
                                            path = "POST/"+urlPrefix + (postMethod.value().length == 0 ? "" :
                                                    "/".equals(String.valueOf(postMethod.value()[0].charAt(0))) ? postMethod.value()[0] :
                                                            "/"+postMethod.value()[0]);
                                            value = AuthPacking.packing(space.value(), auth.value(),"POST", path);
                                        } else if ((putMethod = method.getAnnotation(PutMapping.class)) != null) {
                                            path = "PUT/"+urlPrefix + (putMethod.value().length == 0 ? "" :
                                                    "/".equals(String.valueOf(putMethod.value()[0].charAt(0))) ? putMethod.value()[0] :
                                                            "/"+putMethod.value()[0]);
                                            value = AuthPacking.packing(space.value(), auth.value(),"PUT", path);
                                        } else if ((deleteMethod = method.getAnnotation(DeleteMapping.class)) != null) {
                                            path = "DELETE/"+urlPrefix + (deleteMethod.value().length == 0 ? "" :
                                                    "/".equals(String.valueOf(deleteMethod.value()[0].charAt(0))) ? deleteMethod.value()[0] :
                                                            "/"+deleteMethod.value()[0]);
                                            value = AuthPacking.packing(space.value(), auth.value(),"DELETE", path);
                                        }
                                        RedissonUtil.set(redissonClient, SurroundContent.AUTH_MENU_KEY + ":" + path, JSON.toJSONString(value));
                                    }
                                }
                            }
                        }
                    }
                    System.out.println("lucifer-security-service初始化配置：end");
                }catch (Exception e){
                    System.err.println("lucifer-security业务出错");
                    e.printStackTrace();
                }finally {
                    // 释放业务锁
                    lock.unlock();
//                    System.out.println("lucifer-security业务锁释放");
                }
            }
        }
    }

    /**
     * RequestMapping路径格式化(前后缀‘/’)
     *
     * @param declaredAnnotation
     * @return
     */
    private String urlFormat(RequestMapping declaredAnnotation) {
        String requestMapping = declaredAnnotation.value()[0];
        // 前‘/’处理
        String urlPrefix = ("/".equals(String.valueOf(requestMapping.charAt(0))) ? requestMapping.substring(1) : requestMapping);
        // 后‘/’处理
        if ("/".equals(String.valueOf(urlPrefix.charAt(urlPrefix.length() - 1)))){
            urlPrefix = urlPrefix.substring(0, urlPrefix.length() - 1);
        }
        return urlPrefix;
    }

}
